package main.userdb;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;

import main.Main;
import database.dbObjects.IDBObject.DBObject;
import java.io.File;

public class UserDatabase extends DBObject {
	
    public final void init() throws Exception {
        createTable();
    }
	
	public final boolean createUserDBFile() {
		// Check if file exists and if necessary make 1
        File f = new File(Main.userDBName);
        if (f.exists()) {
        	if (!f.delete()) {
        		return false;
        	}
        }
        try {
        	if (!f.createNewFile()) {
        		return false;
        	}
        } catch (Exception e) {
        	return false;
        }
        
        // TODO setReadable(false) ??
        
        return true;
	}
	
	public final boolean isEmpty() {
		
		try {
			Statement stat = Main.userDBConnection.createStatement();
			ResultSet rs = stat.executeQuery("select * from User;");
			if (rs.next()) {
				rs.close();
				return false;
			} else {
				rs.close();
				return true;
			}
		} catch (Exception e) {
			// TODO unexpected error!!
		}
		return true;
	}
	
	public final boolean add(String user, String password, String dbFile) throws Exception {
		
		checkConsistance(user, password, dbFile);
		
		Vector<Object> v = new Vector<Object>(3);
		v.add(0, user);
		v.add(1, password);
		v.add(2, dbFile);
		
		return super.add("User", v);
	}
	
	public final boolean delete(String user, String password) throws Exception {
		
		checkUserKeys(user, password);
		
		Vector<Object> keys = new Vector<Object>(2);
		keys.add(0, user);
		keys.add(1, password);
		
		return super.delete("User", keyColumns, keys);
	}

    public final boolean delete(String filename) throws Exception {

		checkDBFilename(filename);

		return super.delete("User", "Filename", filename);
	}
	
	public final boolean updateUsername(String user, String password, String newUser) throws Exception {
		
		checkUserKeys(user, password);
		checkUsername(newUser);
		
		Vector<Object> keys = new Vector<Object>(2);
		keys.add(0, user);
		keys.add(1, password);
		
		return super.update("User", keyColumns, keys, "Username", newUser);
	}
	
	public final boolean updatePassword(String user, String password, String newPassword) throws Exception {
		
		checkUserKeys(user, password);
		checkUsername(newPassword);
		
		Vector<Object> keys = new Vector<Object>(2);
		keys.add(0, user);
		keys.add(1, password);
		
		return super.update("User", keyColumns, keys, "Password", newPassword);
	}
	
	public final boolean updateDBFilename(String user, String password, String newDBFile) throws Exception {
		
		checkUserKeys(user, password);
		checkDBFilename(newDBFile);
		
		Vector<Object> keys = new Vector<Object>(2);
		keys.add(0, user);
		keys.add(1, password);
		
		return super.update("User", keyColumns, keys, "Filename", newDBFile);
	}
	
	public final String getDBFilename(String user, String password) throws SQLException {
		
		Statement stat = Main.userDBConnection.createStatement();
		ResultSet rs = stat.executeQuery("select Filename from User " +
										 "where ((Username = '" + user + "') and " +
										 "(Password = '" + password + "'));");
		if (rs.next()) {
			String dbFile = rs.getString("FileName");
			rs.close();
			return dbFile;
		}
		rs.close();
		return null;
	}

    @Override
    protected final void executeCreation(String query) throws Exception {

			if ((query == null) || (query.isEmpty())) {
				throw (new Exception("Query string can't be null or empty!!!"));
			}
	    	Statement stat = Main.userDBConnection.createStatement();
	        stat.executeUpdate(query);
	        stat.close();
	}
    
    private final void createTable() throws Exception {
		
		String query = "create table User( " +
		   			   "Username varchar(" + maxLengthUsername + ") not null, " + 
		   			   "Password varchar(" + maxLengthPassword + ") not null," + 
		   			   "Filename varchar(" + maxLengthFilename + ") unique not null, " + 
		   			   "primary key (Username, Password));";
		executeCreation(query);
	}
	
	private final void checkConsistance(String user, String password, String dbFile) throws Exception {
		
		checkUsername(user);
		checkPassword(password);
		checkDBFilename(dbFile);
	}
	
	private final void checkUserKeys(String user, String password) throws Exception {
		
		checkUsername(user);
		checkPassword(password);
	}
	
	private final void checkUsername(String user) throws Exception {
		
		if (user == null) { throw (new Exception("UserBD: username can't be null!")); }
		if (user.length() > maxLengthUsername) {
			throw (new Exception("UserDB: username exceeds maximum length (" + 
					maxLengthUsername + " characters)!"));
		}
	}
	
	private final void checkPassword(String password) throws Exception {
		
		if (password == null) { throw (new Exception("UserBD: password can't be null!")); }
		if (password.length() > maxLengthPassword) {
			throw (new Exception("UserDB: password exceeds maximum length (" + 
					maxLengthPassword + " characters)!"));
		}
	}
	
	private final void checkDBFilename(String dbFile) throws Exception {
		
		if (dbFile == null) { throw (new Exception("UserDB: filename needed!")); }
		if (dbFile.length() < 1) {
			throw (new Exception("UserDB: filename must be at least 1 character long!"));
		}
		if (dbFile.length() > maxLengthFilename) {
			throw (new Exception("UserDB: filename exceeds maximum length " +
				"(" + maxLengthFilename + " characters)!"));
		}
		File f = new File(dbFile);
		if (!f.exists()) {
			throw (new Exception("UserDB: The file does not exist or the " +
					"given pathname is incorrect!"));
		}
	}
	
	
	private final static Vector<String> keyColumns = new Vector<String>(2);
	static {
		keyColumns.add(0, "Username");
		keyColumns.add(1, "Password");
	}
	private final static int maxLengthUsername = 50;
	private final static int maxLengthPassword = 50;
	private final static int maxLengthFilename = 200;
	
}
